package com.yuanmei.views;

import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.PersistableBundle;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import com.leon.lfilepickerlibrary.LFilePicker;
import com.yuanmei.datas.FetchDataService;
import com.yuanmei.datas.PyTdxBase;
import com.yuanmei.datas.TdxStockInfoRealm;
import com.yuanmei.model.TdxStockInfo;
import com.yuanmei.views.StockListAdapter.DataListType;
import com.yuanmei.model.StockItem;
import com.yuanmei.model.TradeCalenderRealm;
import com.yuanmei.common.Utils;
import com.yuanmei.git_lite.GitError;
import com.yuanmei.git_lite.GitHelper;

import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmResults;
import ir.mirrajabi.searchdialog.SimpleSearchDialogCompat;
import ir.mirrajabi.searchdialog.core.BaseFilter;

/**
 * An example full-screen activity that shows and hides the system UI (i.e.
 * status bar and navigation/system bar) with user interaction.
 */
public class TuViewActivity extends AppCompatActivity
        implements View.OnClickListener, FetchDataService.MarketListener {
    private final static String TAG = TuViewActivity.class.getName();
    private final static int REQUEST_READ_EXTERNAL_JSON_PERMISSION = 0;
    private final static int REQUEST_WRITE_EXTERNAL_JSON_PERMISSION = 1;
    private final static int REQUEST_PICK_EXTERNAL_JSON_PERMISSION = 2;
    private final static int REQUEST_PICK_ATTENTION_LIST = 1001;
    private final static int REQUEST_ON_START = 1000;

    private ListView mStockListView;
    private StockListAdapter mStockListAdapter;
    private FetchDataService.FetchDataBinder mFetchBinder;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
    }

    @Override
    public void onCreateSupportNavigateUpTaskStack(@NonNull TaskStackBuilder builder) {
        super.onCreateSupportNavigateUpTaskStack(builder);
    }

    private TextView mBtAttentionList;
    private TextView mBtMarketList;
    private TextView mBtPreChooseList;
    private PopupMenu mPatternResultPopMenu;
    private TextView mBtTodayQuoteDataSource;
    private HashMap<View, DataListType> mCtrlViewMap;

    private TextView mTvStockColumnNameHead;
//    private TextView mStockPriceHead;
//    private TextView mStockVolumeHead;

    private View mCurrentListView = null;
    private String mPendingExternalJsonPath = null;

    private static class MainViewMessageHandler extends Handler {
        private final WeakReference<TuViewActivity> mWeakMainActivity;

        private MainViewMessageHandler(TuViewActivity tvActivity) {
            mWeakMainActivity = new WeakReference<>(tvActivity);
        }

        @Override
        public void handleMessage(Message msg) {
            TuViewActivity tvActivity = mWeakMainActivity.get();
            if (tvActivity == null || msg.what > emHandleMessage.values().length) {
                return;
            }
            emHandleMessage type = emHandleMessage.values()[msg.what];
            switch (type) {
                case INIT_MARKET_FETCH:
                    tvActivity.mFetchBinder.initMarketFetch(
                            tvActivity.mStockListAdapter.getAttentionList(), tvActivity);
                    tvActivity.setCurrentStockListView(tvActivity.mBtAttentionList);
                    tvActivity.mStockListAdapter.notifyDataSetChanged();
                    break;
                case UPDATE_DATA_SET:
                    tvActivity.mStockListAdapter.notifyDataSetChanged();
                    break;
                case UPDATE_ATTENTION_LIST_OK:
                    tvActivity.setCurrentStockListView(tvActivity.mBtAttentionList);
                    tvActivity.mStockListAdapter.notifyDataSetChanged();
                    break;
                case UPDATE_PRESELECT_LIST_OK:
                    tvActivity.setCurrentStockListView(tvActivity.mBtPreChooseList);
                    tvActivity.mStockListAdapter.notifyDataSetChanged();
                    break;
                case UPDATE_PROFILE_LIST_OK:
                    tvActivity.setCurrentStockListView(tvActivity.mBtTodayQuoteDataSource);
                    tvActivity.mStockListAdapter.notifyDataSetChanged();
                    break;
                case SHOW_PROFILE_SUMMARY:
                    tvActivity.showIndexSummaryDialog((String) msg.obj);
                    break;
                case SHOW_PATTERN_CHOOSE_MENU:
                    tvActivity.showPatternChoosePopUpMenu(Utils.castList(msg.obj, String.class));
                    break;
                case COMMON_NOTIFY_TOAST:
                    Toast.makeText(tvActivity, (String) msg.obj, Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    }

    private MainViewMessageHandler mMainMessagHandler;

    private enum emHandleMessage {
        INIT_MARKET_FETCH,
        UPDATE_DATA_SET,
        UPDATE_ATTENTION_LIST_OK,
        UPDATE_PRESELECT_LIST_OK,
        UPDATE_PROFILE_LIST_OK,
        COMMON_NOTIFY_TOAST,
        SHOW_PROFILE_SUMMARY,
        SHOW_PATTERN_CHOOSE_MENU,
    }

    private void setCurrentStockListView(View chooseView) {
        for (View view : mCtrlViewMap.keySet()) {
            if (view == chooseView) {
                view.setBackgroundResource(R.color.selected_bg);
                mStockListAdapter.setDataList(mCtrlViewMap.get(view));
                String head = String.format(Locale.CHINA, "股票 %d", mStockListAdapter.getCount());
                mTvStockColumnNameHead.setText(head);
                mCurrentListView = view;
                if (mFetchBinder != null) {
                    mBtTodayQuoteDataSource.setText(mFetchBinder.getTodayQuoteSourceName());
                    mFetchBinder.resetFetchList(mStockListAdapter.getCurrentList());
                }
            } else {
                view.setBackgroundResource(R.color.unselected_bg);
            }
        }
    }

    private void asyncInitLoadStockListFromFile() {
        new Thread(() -> {
            mStockListAdapter.loadStockListFromFile();
            Message.obtain(mMainMessagHandler,
                    emHandleMessage.INIT_MARKET_FETCH.ordinal()).sendToTarget();
        }).start();
    }

    private void asyncImportAttentionFile(final String fPath) {
        QuickStockApplication.doSyncRunaable(() -> {
            if (mStockListAdapter.saveAttentionListToFile(fPath)) {
                Message.obtain(mMainMessagHandler, emHandleMessage.UPDATE_ATTENTION_LIST_OK.ordinal()).sendToTarget();
            }
        });
    }

    private void asyncReplacePreChooseList(String fPath) {
        QuickStockApplication.doSyncRunaable(() -> {
            if (mStockListAdapter.replacePreChooseListFromFile(fPath)) {
                Message.obtain(mMainMessagHandler, emHandleMessage.UPDATE_PRESELECT_LIST_OK.ordinal()).sendToTarget();
            }
        });
    }

    private void loadNewPreChooseList(String path) {
        int permission = ActivityCompat.checkSelfPermission(this,
                "android.permission.READ_EXTERNAL_STORAGE");
        if (permission != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{"android.permission.READ_EXTERNAL_STORAGE"},
                    REQUEST_READ_EXTERNAL_JSON_PERMISSION);
            mPendingExternalJsonPath = path;
        } else {
            asyncReplacePreChooseList(path);
        }
    }

    public String getFilePathByUri(Uri uri) {
        // 以 file:// 开头的
        if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
            return uri.getPath();
        }
        // 以 content:// 开头的
        if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
            String[] proj = {MediaStore.Images.Media.DATA};
            CursorLoader loader = new CursorLoader(getApplicationContext(),
                    uri, proj, null, null, null);
            Cursor cursor = loader.loadInBackground();
            int colIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(colIndex);
        }
        return null;
    }

    @Nullable
    private String getPreChooseListFilePathFromIntent(Intent intent) {
        String intentAction = intent.getAction();
        if (android.content.Intent.ACTION_VIEW.equals(intentAction)) {
            String path = getFilePathByUri(intent.getData());
            if (path != null && path.endsWith(".json")) {
                return path;
            }
        }
        return null;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == REQUEST_READ_EXTERNAL_JSON_PERMISSION) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                asyncReplacePreChooseList(mPendingExternalJsonPath);
            }
            mPendingExternalJsonPath = null;
        } else if (requestCode == REQUEST_WRITE_EXTERNAL_JSON_PERMISSION) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                asyncExportAttentionList();
            }
        } else if (requestCode == REQUEST_PICK_EXTERNAL_JSON_PERMISSION) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                openFilePicker();
            }
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    private class FetchServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mFetchBinder = (FetchDataService.FetchDataBinder) service;
            asyncInitLoadStockListFromFile();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mFetchBinder = null;
        }
    }

    private FetchServiceConnection mFetchServiceConnection;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_tu_view);

        mMainMessagHandler = new MainViewMessageHandler(this);

        mStockListView = findViewById(R.id.block_list);
        mStockListAdapter = new StockListAdapter(this);
        mStockListView.setAdapter(mStockListAdapter);
        mStockListView.setOnItemClickListener((a, v, position, id) -> {
            Intent intent = new Intent(TuViewActivity.this,
                    KlineChartActivity.class);
            StockItem item = mStockListAdapter.getItem(position);
            intent.putExtra("Name", item.name());
            intent.putExtra("NetEaseCode", item.netEaseCode());
            intent.putExtra("IsMarketIndex", item.isMarketIndex());
            intent.putExtra("FinanceInfo", item.getFinanceInfo());
            intent.putExtra("FinancialStatements", item.getFinancialStatements());
            intent.putExtra("MatchDetail", item.getMatchDetail());
            intent.putExtra("TodayOpen", item.getOpen());
            intent.putExtra("TodayPrice", item.getPrice());
            intent.putExtra("TodayHigh", item.getHigh());
            intent.putExtra("TodayLow", item.getLow());
            intent.putExtra("TodayYClose", item.getYestClose());
            if (item.isMarketIndex() && item.code().equalsIgnoreCase("000001")) {
                intent.putExtra("TodayVolume", item.getVolume() / 100);
            } else {
                intent.putExtra("TodayVolume", item.getVolume());
            }
            intent.putExtra("TodayAmount", item.getAmount());
            intent.putExtra("TodayIDate", item.getIDateOfUpdate());
            intent.putExtra("TodayBuys", item.getBuys());
            intent.putExtra("TodaySells", item.getSells());
            startActivity(intent);

        });
        registerForContextMenu(mStockListView);

        mBtAttentionList = findViewById(R.id.attention_list);
        mBtAttentionList.setOnClickListener(this);
        registerForContextMenu(mBtAttentionList);

        mBtPreChooseList = findViewById(R.id.pre_choose_list);
        mBtPreChooseList.setOnClickListener(this);
        //registerForContextMenu(mBtPreChooseList);
        mPatternResultPopMenu = new PopupMenu(this, mBtPreChooseList);
        mPatternResultPopMenu.setOnMenuItemClickListener((item) -> {
            String match_file = sLocalGiteeRepo + File.separator + item.getTitle();
            if (mStockListAdapter.replacePreChooseListFromFile(match_file)) {
                Message.obtain(mMainMessagHandler,
                        emHandleMessage.UPDATE_PRESELECT_LIST_OK.ordinal())
                        .sendToTarget();
            }
            return true;
        });
        mBtPreChooseList.setOnLongClickListener((v) -> {
            QuickStockApplication.doSyncRunaable(() -> {
                if (Utils.flushGitRepo(sRemoteGiteeRepo, sLocalGiteeRepo)) {
                    notifyMessage("刷新预选列表成功");
                } else {
                    notifyMessage("刷新预选列表失败");
                }
            });
            Message message = Message.obtain(mMainMessagHandler,
                    emHandleMessage.SHOW_PATTERN_CHOOSE_MENU.ordinal());
            message.obj = Utils.getMatchedFiles(sLocalGiteeRepo, "match_(.*\\.)json");
            message.sendToTarget();
            return true;
        });

        mBtTodayQuoteDataSource = findViewById(R.id.today_quote_source);
        mBtTodayQuoteDataSource.setOnClickListener(this);

        mBtMarketList = findViewById(R.id.market_list);
        mBtMarketList.setOnClickListener(this);

        mTvStockColumnNameHead = findViewById(R.id.name_head);
        mTvStockColumnNameHead.setOnClickListener(this);

        TextView stockPriceHead = findViewById(R.id.price_head);
        stockPriceHead.setOnClickListener(this);

        TextView stockVolumeHead = findViewById(R.id.volume_head);
        stockVolumeHead.setOnClickListener(this);

        TextView nprHead = findViewById(R.id.NPR_head);
        nprHead.setOnClickListener(this);

        TextView perHead = findViewById(R.id.PER_head);
        perHead.setOnClickListener(this);

        TextView industryHead = findViewById(R.id.industry_head);
        industryHead.setOnClickListener(this);

        TextView tvSearch = findViewById(R.id.search);
        tvSearch.setOnClickListener(this);

        TextView tvPreferences = findViewById(R.id.preferences);
        tvPreferences.setOnClickListener(this);

        SharedPreferences preferences = getSharedPreferences("data", MODE_PRIVATE);
        String preServer = preferences.getString("PyTdxHq_Servers", null);
        if (preServer != null) {
            PyTdxBase.setServer(preServer);
        }

        mCtrlViewMap = new HashMap<>();
        mCtrlViewMap.put(mBtAttentionList, DataListType.ATTENTION_LIST);
        mCtrlViewMap.put(mBtPreChooseList, DataListType.PRE_CHOOSE_LIST);
        mCtrlViewMap.put(mBtMarketList, DataListType.MARKET_INDEX_LIST);

        Intent intent = new Intent(this, FetchDataService.class);
        mFetchServiceConnection = new FetchServiceConnection();
        bindService(intent, mFetchServiceConnection, BIND_AUTO_CREATE);

        String intentPath = getPreChooseListFilePathFromIntent(getIntent());
        if (intentPath != null) {
            loadNewPreChooseList(intentPath);
        } else {
            setCurrentStockListView(mBtAttentionList);
        }

        QuickStockApplication.doSyncRunaable(() -> {
            if (Utils.flushGitRepo(sRemoteGiteeRepo, sLocalGiteeRepo)) {
                String lastCalenderFile = sLocalGiteeRepo + File.separator + "calAll.csv";
                int ret = TradeCalenderRealm.checkAndUpdateCalenderRealm(
                        lastCalenderFile);
                if (0 == ret) {
                    notifyMessage("更新交易日历成功");
                } else if (-1 == ret) {
                    notifyMessage("更新交易日历失败");
                }
                Log.d(TAG, "Before import HuaXi Tdx Stocks info From Json");
                String tdxStocksJson = sLocalGiteeRepo + File.separator + "tdx_stocks.json";
//                String tdxStocksJson = sLocalGiteeRepo + File.separator + "pytdx_fininfo.json";
                TdxStockInfoRealm.importTdxStockInfoDbFromJson(tdxStocksJson);
                Log.d(TAG, "After import  HuaXi Tdx Stocks From Json");
            }
            Log.i(TAG, "do flush git calender over");
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        int permission = ActivityCompat.checkSelfPermission(this,
                "android.permission.WRITE_EXTERNAL_STORAGE");
        if (permission != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{"android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.READ_EXTERNAL_STORAGE"},
                    REQUEST_ON_START);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mFetchServiceConnection != null) {
            unbindService(mFetchServiceConnection);
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        String intentPath = getPreChooseListFilePathFromIntent(intent);
        if (intentPath != null) {
            loadNewPreChooseList(intentPath);
        }
        super.onNewIntent(intent);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Hide ActionBar
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.hide();
        }
    }

    void asyncExportAttentionList() {
        final String fExportPath = "/storage/emulated/0/Download" +
                File.separator + sAttentionSaveFile;
        QuickStockApplication.doSyncRunaable(() -> {
            boolean result = mStockListAdapter.saveAttentionListToPath(fExportPath);
            notifyMessage("保存关注股到:" + fExportPath + (result ? " 成功" : " 失败"));
        });
    }

    void openFilePicker() {
        new LFilePicker()
                .withActivity(TuViewActivity.this)
                .withRequestCode(REQUEST_PICK_ATTENTION_LIST)
                .withStartPath("/storage/emulated/0/Download")
                .withFileFilter(new String[]{".json"})
                .withMaxNum(1)
                .withMutilyMode(false)
                .start();
    }

    void asyncFlushPreChooseList(final String remoteRepo,
                                 final String localRepo,
                                 final boolean isAdd) {
        QuickStockApplication.doSyncRunaable(() -> {
            if (!Utils.flushGitRepo(remoteRepo, localRepo)) {
                return;
            }
            String match_stock_path = localRepo + File.separator + "match_stocks.json";
            if (isAdd) {
                if (mStockListAdapter.appendPreChooseListFromFile(
                        match_stock_path)) {
                    Message.obtain(mMainMessagHandler,
                            emHandleMessage.UPDATE_PRESELECT_LIST_OK.ordinal())
                            .sendToTarget();
                    notifyMessage("从云端添加预选股票成功");
                } else {
                    notifyMessage("从云端添加预选股票为空");
                }
            } else {
                if (mStockListAdapter.replacePreChooseListFromFile(match_stock_path)) {
                    Message.obtain(mMainMessagHandler,
                            emHandleMessage.UPDATE_PRESELECT_LIST_OK.ordinal())
                            .sendToTarget();
                    notifyMessage("导入云端预选股票列表(" +
                            mStockListAdapter.getPreChooseListSize() +
                            ")成功");
                } else {
                    notifyMessage("导入云端预选股票列表失败");
                }
            }
            Log.i(TAG, "flush git pre-choose list over");
        });
    }

    void notifyMessage(String msg) {
        Message message = Message.obtain(mMainMessagHandler,
                emHandleMessage.COMMON_NOTIFY_TOAST.ordinal());
        message.obj = msg;
        message.sendToTarget();
    }

    void asyncExportAttentionListToCloud(final String cloudName,
                                         final String remoteRepo,
                                         final String localRepo,
                                         final String user,
                                         final String password) {
        QuickStockApplication.doSyncRunaable(() -> {
            if (!Utils.flushGitRepo(remoteRepo, localRepo)) {
                notifyMessage("刷新:" + remoteRepo + ", 失败！");
                return;
            }
            String attention_file = localRepo + File.separator + sAttentionSaveFile;
            boolean result = mStockListAdapter.saveAttentionListToPath(attention_file);
            if (!result) {
                notifyMessage("保存文件:" + attention_file + ", 失败！");
            }
            try {
                GitHelper.addAndCommitAndPush(localRepo, user, password,
                        sAttentionSaveFile, "自选股保存");
                notifyMessage("上传自选股到 " + cloudName + " 成功");
            } catch (GitError gitError) {
                notifyMessage("上传自选股 " + cloudName + " 失败, 错误：" + gitError.toString());
            }
            Log.i(TAG, "git push stock attension list over");
        });
    }

    void asyncImportAttentionListFromCloud(final String remoteRepo,
                                           final String localRepo) {
        QuickStockApplication.doSyncRunaable(() -> {
            if (!Utils.flushGitRepo(remoteRepo, localRepo)) {
                notifyMessage("刷新:" + remoteRepo + ", 失败！");
                return;
            }
            String attention_file = localRepo + File.separator + sAttentionSaveFile;
            if (mStockListAdapter.saveAttentionListToFile(attention_file)) {
                Message.obtain(mMainMessagHandler, emHandleMessage.UPDATE_ATTENTION_LIST_OK.ordinal()).sendToTarget();
                notifyMessage("导入 " + attention_file + " 成功");
            } else {
                notifyMessage("导入 " + attention_file + " 失败");
            }
            Log.i(TAG, "import git attention stocks over");
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            if (requestCode == REQUEST_PICK_ATTENTION_LIST) {
                //If it is a file selection mode, you need to get the path collection of all the files selected
                //List<String> list = data.getStringArrayListExtra(Constant.RESULT_INFO);//Constant.RESULT_INFO == "paths"
                List<String> list = data.getStringArrayListExtra("paths");
                String chooseFile = list.get(0); // Single file choose mode
                asyncImportAttentionFile(chooseFile);
            }
        }
    }

    private static final int kContextMenuAddItemToAttentions = 0x1001;
    private static final int kContextMenuDeleteItemFromAttentions = 0x1002;

    private static final int kContextMenuImportAttentionFromLocal = 0x1010;
    private static final int kContextMenuImportAttentionFromGithub = 0x1012;
    private static final int kContextMenuExportAttentionToGithub = 0x1013;

    private static final int kContextMenuImportAttentionFromGitee = 0x1014;
    private static final int kContextMenuExportAttentionToGitee = 0x1015;

    private static final int kContextMenuImportPreChooseFromGithub = 0x1022;
    private static final int kContextMenuImportPreChooseFromGitee = 0x1024;

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        if (v == mBtAttentionList && mCurrentListView == mBtAttentionList) {
            menu.add(0, kContextMenuImportAttentionFromGithub, Menu.NONE, "导入github自选");
            menu.add(0, kContextMenuExportAttentionToGithub, Menu.NONE, "导出自选到github");
            menu.add(0, kContextMenuImportAttentionFromGitee, Menu.NONE, "导入gitee自选");
            menu.add(0, kContextMenuExportAttentionToGitee, Menu.NONE, "导出自选到gitee");
        } else if (v == mBtPreChooseList && mCurrentListView == mBtPreChooseList) {
            menu.add(0, kContextMenuImportPreChooseFromGithub, Menu.NONE, "导入github预选");
            menu.add(0, kContextMenuImportPreChooseFromGitee, Menu.NONE, "导入gitee预选");
        }
        else if (v == mStockListView) {
            if (mCurrentListView == mBtPreChooseList) {
                menu.add(0, kContextMenuAddItemToAttentions, Menu.NONE, "添加到自选");
            } else if (mCurrentListView == mBtAttentionList) {
                menu.add(0, kContextMenuDeleteItemFromAttentions, Menu.NONE, "删除");
            }
        }
    }

    private int getStockItemPosition(MenuItem menuItem) {
        AdapterView.AdapterContextMenuInfo menuInfo =
                (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
        return menuInfo.position;
    }

    private static final String sRemoteGithubRepo = "https://github.com/wuyanmei/wave_res.git";
    private static final String sLocalGithubRepo = "/storage/emulated/0/Download/github_wave_res/";
    private static final String sGithubUser = "jkp2k@163.com";
    private static final String sGithubPassword = "0Jkp114196";

    private static final String sRemoteGiteeRepo = "https://gitee.com/feiniao2000/wave_res.git";
    private static final String sLocalGiteeRepo = "/storage/emulated/0/Download/gitee_wave_res/";
    private static final String sGiteeUser = "feiniao2000";
    private static final String sGiteePassword = "#0*Jkp114196";

    private static final String sAttentionSaveFile = "tuview_attention.json";

    /**
     * 原生自定义 dialog
     */
    private void showIndexSummaryDialog(String indexSummary) {
        @SuppressLint("InflateParams") View view = LayoutInflater.from(this).inflate(R.layout.index_dialog, null);
        final TextView tvIndexSummary = view.findViewById(R.id.index_summary);
        tvIndexSummary.setText(indexSummary);
        AlertDialog.Builder builder = new AlertDialog.Builder(this)
                .setView(view)
                .setTitle("指数分析结果")
                .setIcon(R.mipmap.ic_launcher)
                .setNeutralButton("退出", (dialog, id) -> {
                });

        builder.create().show();
    }

    private void showPatternChoosePopUpMenu(List<String> matched_files) {
        Menu menu = mPatternResultPopMenu.getMenu();
        menu.clear();
        int idx = 0;
        for (String fileName : matched_files) {
            menu.add(0, idx++, Menu.NONE, fileName);
        }
        mPatternResultPopMenu.show();
    }

    @Override
    public boolean onContextItemSelected(MenuItem menuItem) {
        int itemPosition;
        int permission;

        switch (menuItem.getItemId()) {
            case kContextMenuAddItemToAttentions:
                itemPosition = getStockItemPosition(menuItem);
                mStockListAdapter.appendStockToAttentionList(
                        mStockListAdapter.getItem(itemPosition));
                mFetchBinder.resetFetchList(
                        mStockListAdapter.getAttentionList());
                mTvStockColumnNameHead.setText(String.format(Locale.CHINA, "股票 %d", mStockListAdapter.getCount()));
                asyncExportAttentionListToCloud("GitEE", sRemoteGiteeRepo, sLocalGiteeRepo, sGiteeUser, sGiteePassword);
                asyncExportAttentionListToCloud("GitHub", sRemoteGithubRepo, sLocalGithubRepo, sGithubUser, sGithubPassword);
                break;
            case kContextMenuDeleteItemFromAttentions:
                itemPosition = getStockItemPosition(menuItem);
                mStockListAdapter.removeStockFromAttentionList(
                        mStockListAdapter.getItem(itemPosition));
                mFetchBinder.resetFetchList(
                        mStockListAdapter.getAttentionList());
                mTvStockColumnNameHead.setText(String.format(Locale.CHINA, "股票 %d", mStockListAdapter.getCount()));
                asyncExportAttentionListToCloud("GitEE", sRemoteGiteeRepo, sLocalGiteeRepo, sGiteeUser, sGiteePassword);
                asyncExportAttentionListToCloud("GitHub", sRemoteGithubRepo, sLocalGithubRepo, sGithubUser, sGithubPassword);
                break;
            case kContextMenuImportAttentionFromLocal:
                permission = ActivityCompat.checkSelfPermission(this,
                        "android.permission.WRITE_EXTERNAL_STORAGE");
                if (permission != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(this,
                            new String[]{"android.permission.WRITE_EXTERNAL_STORAGE"},
                            REQUEST_PICK_EXTERNAL_JSON_PERMISSION);
                } else {
                    openFilePicker();
                }
                break;
            case kContextMenuImportPreChooseFromGithub:
                asyncFlushPreChooseList(sRemoteGithubRepo, sLocalGithubRepo, false);
                break;
            case kContextMenuImportPreChooseFromGitee:
                asyncFlushPreChooseList(sRemoteGiteeRepo, sLocalGiteeRepo, false);
                break;
            case kContextMenuExportAttentionToGithub:
                asyncExportAttentionListToCloud("GitHub", sRemoteGithubRepo, sLocalGithubRepo, sGithubUser, sGithubPassword);
                break;
            case kContextMenuImportAttentionFromGithub:
                asyncImportAttentionListFromCloud(sRemoteGithubRepo, sLocalGithubRepo);
                break;
            case kContextMenuExportAttentionToGitee:
                asyncExportAttentionListToCloud("GitEE", sRemoteGiteeRepo, sLocalGiteeRepo, sGiteeUser, sGiteePassword);
                break;
            case kContextMenuImportAttentionFromGitee:
                asyncImportAttentionListFromCloud(sRemoteGiteeRepo, sLocalGiteeRepo);
                break;
            default:
                return super.onContextItemSelected(menuItem);
        }
        return true;
    }

    private ArrayList<TdxStockInfo> mPublishedResults;

    @SuppressWarnings("unchecked")
    private void showSearchDialog() {
        final SimpleSearchDialogCompat<TdxStockInfo> searchDialog =
                new SimpleSearchDialogCompat(this, "添加自选",
                        "请输入代码、名字或拼音简写...?", null, new ArrayList(),
                        (dialog, item, position) -> {
                            if (mPublishedResults != null) {
                                final TdxStockInfo fStock = mPublishedResults.get(position);
                                Toast.makeText(TuViewActivity.this, fStock.getName() + " 加入自选",
                                        Toast.LENGTH_SHORT).show();
                                Log.i(TAG, "Success add result to attention list");
                                new Thread(() -> {
                                    StockItem chooseItem = new StockItem(fStock.getName(),
                                            String.format(Locale.CHINA, "%06d", fStock.getCode()),
                                            fStock, false);
                                    mStockListAdapter.appendStockToAttentionList(chooseItem);
                                    mFetchBinder.resetFetchList(mStockListAdapter.getAttentionList());
                                }).start();
                            }
                            dialog.dismiss();
                        }
                );

        BaseFilter apiFilter = new BaseFilter() {

            @Override
            protected FilterResults performFiltering(CharSequence keyChars) {
                doBeforeFiltering();
                FilterResults results = null;

                RealmConfiguration stockInfoConfig = new RealmConfiguration.Builder()
                        .name(TdxStockInfoRealm.RealmName)
                        .deleteRealmIfMigrationNeeded()
                        .build();
                Realm realm = Realm.getInstance(stockInfoConfig);
                RealmResults<TdxStockInfo> realmResults;
                if (Character.isDigit(keyChars.charAt(0))) {
                    realmResults = realm.where(TdxStockInfo.class).
                            like("code", keyChars.toString().toUpperCase() + "*").findAll();
                } else if (Character.isAlphabetic(keyChars.charAt(0))) {
                    realmResults = realm.where(TdxStockInfo.class).
                            like("pinyin", keyChars.toString().toUpperCase() + "*")
                            .findAll();
                } else {
                    realmResults = realm.where(TdxStockInfo.class).
                            like("name", keyChars.toString().toUpperCase() + "*")
                            .findAll();
                }

                if (realmResults != null && realmResults.size() > 0) {
                    List<TdxStockInfo> realmList = realm.copyFromRealm(realmResults);
                    results = new FilterResults();
                    results.values = realmList;
                    results.count = realmList.size();
                }
                realm.close();
                return results;
            }

            @Override
            @SuppressWarnings("unchecked")
            protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
                if (filterResults != null) {
                    ArrayList<TdxStockInfo> filtered =
                            (ArrayList<TdxStockInfo>) filterResults.values;
                    if (filtered != null) {
                        searchDialog.getFilterResultListener().onFilter(filtered);
                        mPublishedResults = filtered;
                    }
                    doAfterFiltering();
                }
            }
        };
        searchDialog.setFilter(apiFilter);
        searchDialog.show();
    }

    private void showPreferencesDialog() {
        @SuppressLint("InflateParams")
        View view = this.getLayoutInflater().inflate(R.layout.preferences_dialog, null);
        Spinner tdx_spinner = view.findViewById(R.id.tdx_spinner);
        ArrayAdapter adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_spinner_item, PyTdxBase.SERVERS);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        tdx_spinner.setAdapter(adapter);
        tdx_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(TuViewActivity.this, "选中的服务器是: " + PyTdxBase.SERVERS[position], Toast.LENGTH_LONG).show();
                SharedPreferences.Editor editor = TuViewActivity.this.getSharedPreferences("data", MODE_PRIVATE).edit();
                editor.putString("PyTdxHq_Servers", PyTdxBase.SERVERS[position]);
                editor.apply();
                PyTdxBase.setServer(PyTdxBase.SERVERS[position]);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                PyTdxBase.setServer(PyTdxBase.SERVERS[0]);
            }
        });
        AlertDialog.Builder builder = new AlertDialog.Builder(this)
                .setView(view);
        builder.create().show();
    }

    private void toggleTodayQuoteSource() {
        if (mFetchBinder != null) {
            mFetchBinder.toggleTodayQuoteSource();
            mBtTodayQuoteDataSource.setText(mFetchBinder.getTodayQuoteSourceName());
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.attention_list:
                setCurrentStockListView(mBtAttentionList);
                break;
            case R.id.pre_choose_list:
                setCurrentStockListView(mBtPreChooseList);
                break;
            case R.id.today_quote_source:
                toggleTodayQuoteSource();
                break;
            case R.id.market_list:
                setCurrentStockListView(mBtMarketList);
                break;
            case R.id.preferences:
                showPreferencesDialog();
                break;
            case R.id.search:
                showSearchDialog();
                break;
            case R.id.name_head:
                mStockListAdapter.sortCurrentListByStockCode();
                break;
            case R.id.price_head:
                mStockListAdapter.sortCurrentListByPricePercent();
                break;
            case R.id.volume_head:
                mStockListAdapter.sortCurrentListByVolumePercent();
                break;
            case R.id.NPR_head:
                mStockListAdapter.sortCurrentListByNetAssetsOperateProfitRatio();
                break;
            case R.id.PER_head:
                mStockListAdapter.sortCurrentListByPriceEarningsRatio();
                break;
            case R.id.industry_head:
                mStockListAdapter.sortCurrentListByIndustry();
                break;
            default:
                break;
        }
    }

    private boolean mIsActivityFront = false;

    @Override
    public void onResume() {
        super.onResume();
        mIsActivityFront = true;
        if (mFetchBinder != null) {
            mFetchBinder.registerMarketListener(this);
            mFetchBinder.flushStockData();
        }
        this.runOnUiThread(() -> mStockListAdapter.notifyDataSetChanged());
    }

    @Override
    public void onPause() {
        super.onPause();
        mIsActivityFront = false;
        if (mFetchBinder != null)
            mFetchBinder.unregisterMarketListener(this);
    }

    @Override
    public void onTodayQuotesFetched(ArrayList<String> quotesList) {
        int count = mStockListAdapter.updateTodayQuotes(quotesList);
        if (mIsActivityFront) {
            int indexCount = mStockListAdapter.getMarketIndexCount();
            int stockCount = Math.min(count, quotesList.size());
            if (stockCount > indexCount) {
                stockCount -= indexCount;
                notifyMessage("已更新" + stockCount +
                        "只股票及" + indexCount + "支指数的实时交易数据");

            } else if (stockCount == indexCount) {
                notifyMessage("已更新 " + stockCount +
                        "只指数的实时交易数据");
            } else {
                notifyMessage("已更新 " + stockCount +
                        "只股票或指数的实时交易数据");
            }
        }
        this.runOnUiThread(() -> mStockListAdapter.notifyDataSetChanged());
    }

    @Override
    public void onTodayMinuteTickQuoteFetched(String neCode) {
        mStockListAdapter.updateTodayMinuteTickQuote(neCode);
        this.runOnUiThread(() -> mStockListAdapter.notifyDataSetChanged());
    }


}
